#ifndef _PROCESS_POOL_HPP_
#define _PROCESS_POOL_HPP_
#include<iostream>
#include<vector>
#include<cstdlib>
#include<unistd.h>//fork
#include<sys/wait.h>
#include"Task.hpp"
//先描述
class Channel
{
public:
    Channel(int wfd , int subid)
    :_wfd(wfd),
    _subid(subid)
    {
        _name = "Channel-" + std::to_string(_wfd) + "-" + std::to_string(_subid);
    }
    ~Channel()
    {

    }
    std::string& Name()
    {
        return _name;
    }
    void Send(int code)
    {
        int n = write(_wfd,&code,sizeof(code));
        (void) n;
    }
    void Close()
    {
        close(_wfd);
    }
    void Wait()
    {
        pid_t rid = waitpid(_subid,nullptr,0);
        (void) rid;
    }
private:
    int _wfd;
    int _subid;
    std::string _name;
};
//在组织
class ChannelManager
{
public:
    ChannelManager()
    :_next(0)
    {
        ;
    }
    ~ChannelManager()
    {
        ;
    }
    Channel& Select()
    {
        auto& c = _channels[_next];
        _next = (_next + 1) % _channels.size();
        return c;
    }
    void Insert(int wfd , int subid)
    {
        _channels.emplace_back(wfd,subid);//通过自定义类型的默认构造,创建自定义类型的对象,并尾插
    }
    void StopSubProcess()
    {
        for(auto& x : _channels)
        {
            x.Close();
            std::cout << "关闭: " << x.Name() << std::endl;
        }
    }
    void WaitSubProcess()
    {
        for(auto& x : _channels)
        {
            x.Wait();
            std::cout << "回收: " << x.Name() <<  std::endl;
        }
    }
    //会有问题因为子进程拷贝自父进程,父进程读取上一个管道的文件描述符也被子进程给继承了
    void AllSubProcess()
    {
        
        for(auto& x : _channels)
        {
            x.Close();
            std::cout << "关闭: " << x.Name() << std::endl;
            x.Wait();
            std::cout << "回收: " << x.Name() <<  std::endl;
        }
        /*
        //解决方法1(反向遍历)
        for(int i = _channels.size() - 1; i >= 0; i--)
        {
            _channels[i].Close();
            std::cout << "关闭: " << _channels[i].Name() << std::endl;
            _channels[i].Wait();
            std::cout << "回收: " << _channels[i].Name() <<  std::endl;
        }*/
    }
    void AllClode()
    {
        for(auto& x : _channels)
        {
            x.Close();
           // std::cout << "关闭: " << x.Name() << std::endl;
        }
    }
private:
    std::vector<Channel> _channels;//管理通信的信道
    int _next;//轮训选择信道的下标
};



class ProcessPool 
{
public:
    ProcessPool(int num)//注册任务
    :_process_num(num)
    {
        _tm.Register(PrintLog);
        _tm.Register(Download);
        _tm.Register(Upload);
    }
    void Work(int rfd)
    {
        while(true)
        {
            int code = 0;
            ssize_t n = read(rfd,&code,sizeof code);//子进程会等待父进程的输入,若该信道没有输入,会阻塞等待,成功返回读取的大小,写端关闭返回0,读取失败返回-1
            if(n > 0)
            {
                if(n != sizeof(code))//读取数据出错,重新读取
                {
                    continue;
                }
                _tm.Execute(code);
                std::cout << "子进程[" << getpid() << "]收到一个任务码: " << code << std::endl;//打印一下收到的任务码

            }
            else if(n == 0)
            {
                std::cout << "子进程退出" << std::endl;
                break;
            }
            else
            {
                std::cout << "读取错误" << std::endl;
            }
        }
    }
    bool Start()
    {
        for(int i = 0; i < _process_num;i++)
        {
            //创建管道
            int pipefd[2] = {0};//定义一个数组存储描述符信息
            int n = pipe(pipefd);//创建通信管道,失败返回-1
            if(n < 0)
            {
                return false;
            }
            //创建子进程
            pid_t subid = fork();//创建失败返回-1，成功子进程返回0，父进程返回子进程的pid;
            
            if(subid < 0)
            {
                return  false;
            }
            else if(subid == 0)
            {
                //子进程
                //关闭哥哥进程的写功能
                _cm.AllClode();
                //关闭不需要的文件描述符-w
                close(pipefd[1]);//关闭w
                Work(pipefd[0]);//执行子进程的任务
                close(pipefd[0]);//关闭r
                exit(0);//退出子进程
            }
            else
            {
                //父进程
                //关闭父进程不需要的描述符-r
                close(pipefd[0]);
                _cm.Insert(pipefd[1],subid);//传入读描述符,和子进程的pid建立关系
            }
        }
        return true;
    }
    void Run()
    {
        int taskcode = _tm.Code();//随机选择一个任务
        auto &c = _cm.Select();//随机获取一个进程
        std::cout << "选择了一个子进程: " << c.Name() << std::endl;//输出进程信息
        c.Send(taskcode);//向进程发送任务吗
        std::cout << "发送了一个任务码: " << taskcode << std::endl;
    }
    void Stop()
    {
        //关闭父进程所有的wfd
       
        //_cm.StopSubProcess();
        //_cm.WaitSubProcess();
        _cm.AllSubProcess();
    }
private:
    ChannelManager _cm;
    int _process_num;
    TaskManager _tm;
};

#endif